package com.fary.controller;

import com.fary.po.User;
import com.fary.service.HelloService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Controller;
import org.springframework.util.concurrent.ListenableFuture;
import org.springframework.validation.Errors;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.client.AsyncRestTemplate;
import org.springframework.web.context.request.async.DeferredResult;
import org.springframework.web.context.request.async.WebAsyncTask;

import javax.servlet.AsyncContext;
import javax.servlet.AsyncEvent;
import javax.servlet.AsyncListener;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.concurrent.Callable;

@RequestMapping
@Controller
public class AsyncController {

    @Autowired
    private HelloService helloService;

    /**
     * Servlet 异步
     */
    @PostMapping("/test")
    @ResponseBody
    public void test(@RequestBody User user, Errors errors, HttpServletRequest request) {
        //获取异步上下文
        AsyncContext asyncContext = request.startAsync();
        asyncContext.addListener(new AsyncListener() {
            @Override
            public void onComplete(AsyncEvent event) throws IOException {

            }

            @Override
            public void onTimeout(AsyncEvent event) throws IOException {

            }

            @Override
            public void onError(AsyncEvent event) throws IOException {

            }

            @Override
            public void onStartAsync(AsyncEvent event) throws IOException {

            }
        });
        //开启异步处理过程
        asyncContext.start(() -> {
            //耗时处理
            try {
                Thread.sleep(2000);
                //通过AsyncContext返回 respsonse
                asyncContext.getResponse().getWriter().write("Hello World1!");
            } catch (Exception e) {
                e.printStackTrace();
            }
            //异步处理完成
            asyncContext.complete();
        });
        System.out.println(user.getName());
    }

    @PostMapping("/test1")
    @ResponseBody
    public WebAsyncTask<User> test1() {
        Callable<User> callable = () -> {
            System.out.println("异步请求开始,线程为" + Thread.currentThread());
            Thread.sleep(1000);
            System.out.println("异步请求结束,线程为" + Thread.currentThread());
            return new User("1", "zhangsan");
        };
        System.out.println("请求结束,线程为" + Thread.currentThread());
        WebAsyncTask<User> webAsyncTask = new WebAsyncTask<User>(callable);
        webAsyncTask.onTimeout(new Callable<User>() {
            @Override
            public User call() throws Exception {
                return new User("1", "请求已超时");
            }
        });
        return webAsyncTask;
    }

    @PostMapping("/test2")
    @ResponseBody
    public Callable<String> test2() {
        return () -> {
            Thread.sleep(5 * 1000L);
            System.out.println("Callable处理执行中。。。");
            return "久等了";
        };
    }

    @PostMapping("/test3")
    @ResponseBody
    public DeferredResult<String> test3() {
        final DeferredResult<String> result = new DeferredResult<String>(7*1000L, "超时了");
        approve(result);
        return result;
    }
    private void approve(DeferredResult<String> result){
        Runnable r = new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(5 * 1000L);
                    result.setResult("同意 "+new SimpleDateFormat("yyyy-MM-dd").format(new Date()));
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        };
        new Thread(r).start();
    }

    @PostMapping("/test4")
    @ResponseBody
    public ListenableFuture<ResponseEntity<String>> test4() {
        ListenableFuture<ResponseEntity<String>> future = new AsyncRestTemplate().getForEntity(
                "http://localhost:8080/index", String.class);
        return future;
    }
}
